﻿#define _CRT_SECURE_NO_WARNINGS 1
// 小明今天外出野炊。他的母亲为他制作了M种他喜欢的饼干，共有N块。每块饼干都被标了编号，从1一直标到N。
// 第i块饼干的重量是W[i]。饼干种类的编号是T[i]，从1一直到M。小明想尽可能拿到最大总重量的饼干，但每种饼干只拿一块，
//而且他的背包的最大承重不能超过C。请帮助小明进行选择，别忘了要确保每种饼干至少拿一块。
#include<iostream>
#include<vector>
#include<unordered_map>
#include<cstdio>
using namespace std;
int main()
{
	//N是总数，M是种类数，C是背包重量
	//用二维数组存放每种饼干
	int M, N, C;
	scanf("%d%d%d", &N, &M, &C);
	vector<int> W(N);
	vector<int> T(N);
	//分组
	unordered_map<int, int> S;
	vector<int> dp(N);
    int sum = 0;
	for (int i = 0; i < N; i++)
	{
		scanf("%d", &W[i]);
	}
	for (int i = 0; i < N; i++)
	{
		scanf("%d", &T[i]);
	}
    for (int i = 0; i < N; i++)
    {
        if (S.find(T[i]) == S.end())
        {
            S[T[i]] = i;
            if (dp[i] + W[i] < C)
                dp[i] += W[i];
        }
        else
        {
            if (dp[i-1]-S[T[i]] + W[i] > dp[i-1] && dp[i - 1] - S[T[i]] + W[i] <= C)
            {
                S[T[i]] = W[i];
                dp[i] = dp[i - 1] - S[T[i]] + W[i];
            }
            else {
                dp[i] = dp[i - 1];
            }
        }
    }
    for (int i = 1; i <= M; i++)
    {
        printf("%d ", W[S[i]]);
        sum += S[i];
    }
    printf("\n%d", sum);
	return 0;
}
/*大美给她的四个孩子，小明、小红、小花、小虎去超市买糖果。货架上已经依次摆放了N个糖果，并且每个糖果都有一个“美味值”参数，第“i” 个糖果的美味值是xi。

大美打算从小明开始从第一个糖果依次拿一些糖果；接着让小红依次拿一些糖果，然后让小花依次拿一些糖果，最后让小虎拿走剩余糖果。等孩子们都拿到糖果后，再一起统计一下各自拿到的总美味值。

大美想尽可能缩小得到最大美味值和孩子和得到最小美味值的孩子之间的美味值差距，以防止孩子抱怨。请指导一下大美该如何让孩子们拿糖果。*/
//#include<iostream>
//#include<cstdio>
//#include<vector>
//using namespace std;
//int main()
//{
//	vector<int> kid(4);
//	int n;
//	int ma = 0;
//	int mi = INT_MAX;
//	scanf("%d", &n);
//	vector<int>value(n);
//	int sum = 0;
//	for (int i = 0; i < n; i++)
//	{
//		scanf("%d", &value[i]);
//		sum += value[i];
//	}
//	int eve = sum / 4;
//	int poi = 0;
//	for (int i = 0; i < 4; i++) {
//		for (int j = poi; j < n; j++) {
//			if (poi + (3 - i) < n)
//			{
//				if (kid[i] < eve)
//				{
//					kid[i] += value[j];
//					poi++;
//				}
//				else
//				{
//					break;
//				}
//			}
//		}
//	}
//	ma = kid[0];
//	mi = kid[0];
//	for (int i = 1; i < 4; i++)
//	{
//		ma = max(ma, kid[i]);
//		mi = min(mi, kid[i]);
//	}
//	printf("%d", ma - mi);
//	return 0;
//}
/*国际日期格式标准建议按照年、月、日的顺序来显示日期：YYYY - MM - DD.

然而，有些人喜欢使用MMDDYY顺序，而也有人喜欢使用DDMMYY顺序。

MMDDYY : 两位数字MM表示月份，两位数字DD表示日期，两位数字YY表示年份。

DDMMYY : 两位数字DD表示日期，两位数字MM表示月份，两位数字YY表示年份。

例如，2023年3月24日可以被写为03 / 24 / 23或者24 / 03 / 23。如果给你一个像这样的一个字符串，你得能判断出这是哪种日期格式。

如果这个日期仅能用MMDDYY格式来理解才是一个合法的日期，就打印显示“MMDDYY”;

如果这个日期仅能用DDMMYY格式来理解才是一个合法的日期，就打印显示“DDMMYY”;

如果这个日期以两种格式去理解都是合法的日期，就打印显示“BOTH”;

如果这个日期在任何格式下都不是一个合法日期，就打印显示“NOTHING”*/
//03/24/23
//#include<iostream>
//#include<vector>
//using namespace std;
//int main() 
//{
//	vector<int> judge(3);
//	char ques[9];
//	scanf("%s", ques);
//	int flag = 0;
//	judge[0] = (ques[0] - '0') * 10 + (ques[1] - '0');
//	judge[1] = (ques[3] - '0') * 10 + (ques[4] - '0');
//	judge[2] = (ques[6] - '0') * 10 + (ques[7] - '0');
//	if (judge[0] <= 12 && judge[1] <= 12) {
//		printf("BOTH");
//		return 0;
//	}
//	if (judge[2] % 4 == 0) {
//		if (judge[0] <= 12 && judge[1] > 12&&judge[1]<=31)
//		{
//			switch (judge[0])
//			{
//			case 1:
//			case 3:
//			case 5:
//			case 7:
//			case 8:
//			case 10:
//			case 12:printf("MMDDYY");
//				return 0;
//			case 2:if (judge[1] <= 29)
//				printf("MMDDYY");
//				  else
//				printf("NOTHING");
//				return 0;
//			default:
//				if(judge[1]>=31)
//					printf("NOTHING");
//				else
//					printf("MMDDYY");
//				return 0;
//				break;
//			}
//		}
//		else if (judge[1] <= 12 && judge[0] > 12 && judge[0] <= 31) {
//			switch (judge[1])
//			{
//			case 1:
//			case 3:
//			case 5:
//			case 7:
//			case 8:
//			case 10:
//			case 12:printf("DDMMYY");
//				return 0;
//			case 2:if (judge[0] <= 29)
//				printf("DDMMYY");
//				  else
//				printf("NOTHING");
//				return 0;
//			default:
//				if (judge[0] >= 31)
//					printf("NOTHING");
//				else
//					printf("MMDDYY");
//				return 0;
//				break;
//			}
//		}
//		else {
//			printf("NOTHING");
//			return 0;
//		}
//	}
//	else {
//		if (judge[0] <= 12 && judge[1] > 12 && judge[1] <= 31)
//		{
//			switch (judge[0])
//			{
//			case 1:
//			case 3:
//			case 5:
//			case 7:
//			case 8:
//			case 10:
//			case 12:printf("MMDDYY");
//				return 0;
//			case 2:if (judge[1] <= 28)
//				printf("MMDDYY");
//				  else
//				printf("NOTHING");
//				return 0;
//			default:
//				if (judge[1] >= 31)
//					printf("NOTHING");
//				else
//					printf("MMDDYY");
//				return 0;
//				break;
//			}
//		}
//		else if (judge[1] <= 12 && judge[0] > 12 && judge[0] <= 31) {
//			switch (judge[1])
//			{
//			case 1:
//			case 3:
//			case 5:
//			case 7:
//			case 8:
//			case 10:
//			case 12:printf("DDMMYY");
//				return 0;
//			case 2:if (judge[0] <= 28)
//				printf("DDMMYY");
//				  else
//				printf("NOTHING");
//				return 0;
//			default:
//				if (judge[0] >= 31)
//					printf("NOTHING");
//				else
//					printf("MMDDYY");
//				return 0;
//				break;
//			}
//		}
//		else {
//			printf("NOTHING");
//			return 0;
//		}
//	}
//	return 0;
//}
/*今天，小刚在王教授的离散数学课上学习了逆序对。



逆序对是离散数学中的一个概念，是指在一个序列中，按照一定的大小比较方法，序列中任两个元素大小顺序颠倒的组合。



同时满足以下两个条件，(a[i], a[j])就被称为序列中的一个逆序对：

1. a[i] > a[j]

2. i < j



    王教授希望小刚通过编程来求解一个序列中逆序对的个数，而且不是通过手工计算。小刚擅长离散数学但是并不擅长编程。请帮助小刚解决这个问题。
    */
//#include<iostream>
//#include<vector>
//using namespace std;
//int main()
//{
//    int N;
//    scanf("%d", &N);
//    vector<int> arr(N);
//    for (int i = 0; i < N; i++)
//    {
//        scanf("%d", &arr[i]);
//    }
//    int left = 0;
//    int right = N - 1;
//    int num = 0;
//    while (right > 0)
//    {
//        left = 0;
//        right = N - 1;
//        while (left != right) {
//            while (arr[right] >= arr[0]) {
//                right--;
//                if (right == 0)
//                    break;
//            }
//            while (arr[left] <= arr[0]) {
//                if (left == right)
//                    break;
//                left++;
//            }
//            if (left != right) {
//                num++;
//                int t = arr[left];
//                arr[left] = arr[right];
//                arr[right] = t;
//            }
//            else {
//                int t = arr[0];
//                arr[0] = arr[right];
//                arr[right] = t;
//                num++;
//            }
//        }
//    }
//    printf("\n%d", num);
//    return 0;
//}
/*小强前去面试一份工作。老板说，有个问题你如果能答上来，就能得到这份工作。可是小强怎么也答不上来，场面非常窘迫。老板说：“我不在乎你原来学了什么，我只在乎你能否快速掌握新知识。回家去再想想，如果明天能答上来，就直接来上班。”问题如下：


如果你被给予一个整数N，包含1到9的数字，你可以在这个整数的任意位置插入加号。可以在多个位置插入加号，或者一个也不插入，但是在一个位置上只能插入一个加号，不得连续插入多个加号。这样就能通过加法得到一个新的整数。请计算出按这种方法得到的所有整数的总和。


请帮助小强得到这份工作吧！*/
//#include<iostream>
//#include<vector>
//#include<cstdlib>
//using namespace std;
//typedef long long LL;
//int main()
//{
//    LL sum = 0;
//    string s;
//    scanf("%s", s);
//    vector<int>arr(s.size());
//    for (int i = 0; i < s.size(); i++) {
//        arr[i];
//            sum += atoi(s.c_str());
//    }
//    return 0;
//}
/*数字8、2、6、9是大多数中国人中最喜欢的幸运数字。这几个数字的组合也被视为幸运数字，例如88。



小龙非常喜欢幸运数字。他认为只有满足以下条件的正整数才算是好的整数：



8、2、6、9中的每个数字至少在这个整数中出现一次，而且没有除了这四个之外的其他数字。



小龙想知道在1和N（含N）之间有多少个满足这一条件的整数。*/
//8269
//1234
//#include<iostream>
//#include<vector>
//#include<cstring>
//using namespace std;
//typedef long long LL;
//bool judge(LL x) {
//    int bit = 0;
//    LL a = x;
//    LL b = x;
//    int j[4] = { 0 };
//    while (a > 0) {
//        bit++;
//        a /= 10;
//    }
//    while (bit--)
//    {
//        int flag = x % 10;
//        if (flag != 8 && flag != 2 && flag != 6 && flag != 9) {
//            return false;
//        }
//        switch (flag)
//        {
//        case 8:j[0]++; break;
//        case 2:j[1]++; break;
//        case 6:j[2]++; break;
//        case 9:j[3]++; break;
//        default:
//            break;
//        }
//        x /= 10;
//    }
//    for (int i = 0; i < 4; i++)
//    {
//        if (j[i] == 0)
//            return false;
//    }
//    return true;
//}
//int main()
//{
//    char s[15];
//    scanf("%s", s);
//    vector<int>arr(24);
//    int num = 0;
//    for (int i = 1000; i <= atoi(s); i++)
//    {
//        if (judge(i))
//            num++;
//    }
//    printf("%d", num);
//    return 0;
//}
/*很久很久以前, 在一个国家里有N个村庄。起初，这N个村庄相互之间通过M座桥梁相连，桥梁从1到M进行编号。第i座桥在第Ai​个村庄和第Bi​个村庄之间进行连接。因此人们可以在任意两个村庄之间利用这些桥梁进行通行。

为了阻止人们相互联络，入侵者决定一个接一个地毁坏这些桥梁。从第1座桥开始，依次摧毁，直至第K(1 <= K <= M)座桥。

村庄a和村庄b组成一个村庄组合(a, b)(a < b)，当第一座桥到第K座桥被依次摧毁后，计算到底有多少个 (a, b)(a < b)这样的村庄组合不能通过剩余的一座或多座桥梁进行来往通行。*/
/*输入
第一行包含三个整数N, M, K,分别表示村庄总数、桥梁总数和被摧毁的桥梁数目。

接着有M行，每一行包含两个整数ai, bi，表示由第i座桥梁连接着的两个村庄的编号。*/
//#include<vector>
//#include<iostream>
//using namespace std;
//int main()
//{
//    int N, M, K;
//    vector<pair<int, int>> house;
//    scanf("%d%d%d", &N, &M, &K);
//    for (int i = 0; i < M; i++) {
//        int a, b;
//        scanf("%d%d", &a, &b);
//        house.push_back(pair<int,int>(a,b));
//    }
//    return 0;
//}
/*今天，小刚在王教授的离散数学课上学习了逆序对。



逆序对是离散数学中的一个概念，是指在一个序列中，按照一定的大小比较方法，序列中任两个元素大小顺序颠倒的组合。



同时满足以下两个条件，(a[i],a[j])就被称为序列中的一个逆序对：

       1. a[i] > a[j]

       2. i < j



王教授希望小刚通过编程来求解一个序列中逆序对的个数，而且不是通过手工计算。小刚擅长离散数学但是并不擅长编程。请帮助小刚解决这个问题。*/
//#include<iostream>
//#include<vector>
//using namespace std;
//int main()
//{
//    int N;
//    scanf("%d", &N);
//    vector<int> arr(N);
//    int num = 0;
//    for (int i = 0; i < N; i++)
//    {
//        scanf("%d", &arr[i]);
//    }
//    for (int i = 0; i < N; i++)
//    {
//        for (int j = i + 1; j < N; j++) 
//        {
//            if (arr[j] < arr[i])
//                num++;
//        }
//    }
//    printf("%d", num);
//    return 0;
//}